#include <shm.h>
#include <iostream>
using namespace std;

// P操作
int Shm::P()
{
    return semop(sem_id, &sem_p, 1);
}

// V操作
int Shm::V()
{
    return semop(sem_id, &sem_v, 1);
}


int Shm::shm_init(int SHARE_KEY,int SIGNAL_KEY)
{
	//打开一个信号量集，该信号量集只有一个信号量
    sem_id = semget((key_t) SIGNAL_KEY, 1, IPC_CREAT | 0666);
    if (sem_id == -1)
    {
        perror("semget error!");
        return -1;
    }
    // initial key number
	union semun semopt;
	semopt.val = 1;
	int res = semctl(sem_id, 0, SETVAL, semopt);
	if (res == -1)
	{
		printf("semctl error!\n");
		return -1;
	}

    // 使用约定的键值打开共享内存
    shmid = shmget((key_t) SHARE_KEY, SHM_BUF_SIZE,  0666 | IPC_CREAT);
    //printf("shmid : %u\n", shmid);
    if (shmid < 0)
    {
        perror("shmget error!");
        return -1;
    }

	// 将共享内存附加到本进程
    shm_addr = shmat(shmid, NULL, 0);
    if (shm_addr == (void *) -1)
    {
        perror("shmat error!");
        return -1;
    }
    return 0;
}
string Shm::shm_read()
{     
    // 准备进入临界区
	if (P() == -1)
    {
        printf("P error!\n");
        return "error";
    }
    // 在临界区里面,读取数据
    char tmp[SHM_BUF_SIZE];
    bzero(tmp, SHM_BUF_SIZE);
    memcpy(tmp, shm_addr, SHM_BUF_SIZE);
    
    // 离开临界区
    if (V() == -1)
    {
        printf("V error!\n");
        return "error";
    }
   
    string data;
    for(int i=0;i<SHM_BUF_SIZE;i++)
    {
        if(tmp[i] != '\0')
        data += tmp[i];
        else
            break;
    }
	return data;
}
int Shm::shm_write(string data)
{
    // 准备进入临界区
	if (P() == -1)
    {
        printf("P error!\n");
        return -1;
    }
    // 在临界区里面,write
    char *tmp_data = const_cast<char*>(data.c_str());
    char tmp[SHM_BUF_SIZE];

    bzero(tmp, SHM_BUF_SIZE);
    strcpy(tmp,tmp_data);
    int size = strlen(tmp);

    memcpy(shm_addr, tmp, strlen(tmp)+1);
    
    // 离开临界区
    if (V() == -1)
    {
        printf("V error!\n");
        return -1;
    }

	return 0;
}

int Shm::remove_shm()
{
    // 分离
    if (shmdt(shm_addr) == -1)
    {
        printf("shmdt error!\n");
        return -1;
    }

    // 删除共享内存
    if (shmctl(shmid, IPC_RMID, 0) == -1)
    {
        printf("shmctl error!\n");
        return -1;
    }

    return 0;
} 
